package com.kystar.muxplayer.protocol;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;

public abstract class CodeCmd {
    protected final static byte CODE_START = (byte) 0xe9;
    protected final static byte CODE_END1 = 0x0d;
    protected final static byte CODE_END2 = 0x0a;
    protected final static byte CODE_OK = (byte) 0xaa;
    protected final static byte CODE_DEVICE_ID = (byte) 0x11;//17

    private byte[] mValue;
    protected byte[] mResult;

    protected CodeCmd(byte... params) {//E9 11 8D 00 01 AA 32 0D 0A
        int length = params.length;
        byte sum = 0;
        mValue = new byte[length+8];
        mValue[0] = CODE_START;
        mValue[1] = CODE_DEVICE_ID;//17;
        mValue[2] = getCode();
        mValue[3]= (byte) ((length>>8)&0xFF);
        mValue[4] = (byte) (length&0xFF);
        int k = 5;
        for (int i = 0; i < length; i++) {
            mValue[k++] = params[i];
        }
        for (int i = 0; i < k; i++) {
            sum+= mValue[i];
        }
        mValue[k] = sum;
        k++;
        mValue[k] = CODE_END1;
        k++;
        mValue[k] = CODE_END2;
    }
    protected CodeCmd(int... params) {
        this(int2Bytes(params));
    }
    private static byte[] int2Bytes(int... params) {
        byte[] bytes = new byte[params.length];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) (params[i]&0xFF);
        }
        return bytes;
    }

    public abstract byte getCode();


    public byte[] getValue() {
        return mValue;
    }
    public byte[] getResult() {
        return mResult;
    }

    protected byte readByte(InputStream in) throws IOException {
        return (byte) (in.read()&0xFF);
    }
    protected int readShort(InputStream in) throws IOException {
        return (readByte(in)<<8 | readByte(in)) & 0xFF;
    }

    protected void readBytes(InputStream in, byte[] bytes) throws IOException {
        int len = bytes.length;
        int start = 0;
        while (start < len) {
            int read = in.read(bytes, start, len - start);//TODO 处理一次没有读取完
            if (read == -1) {
                throw new EOFException("EOF");
            }
            start += read;
        }
    }
    public  void process(InputStream in) throws IOException {
        verify(readByte(in), CODE_START, "start");
        verify(readByte(in), CODE_DEVICE_ID, "device");
        verify(readByte(in), getCode(), "code");
//        int len = readShort(in);
//        verify(len, readShort(in), "data length");
        int len = readShort(in);
        byte[] result = new byte[len];
        readBytes(in,result);
        byte sum = CODE_START+CODE_DEVICE_ID;
        sum+= getCode();
        sum+=len;
        for (int i = 0; i < len; i++) {
            sum+= result[i];
        }
        verify(readByte(in), sum, "sum");
        verify(readByte(in), CODE_END1, "end1");
        verify(readByte(in), CODE_END2, "end2");
        mResult = result;
        checkResult();
    }
    protected static void verify(byte value, byte expect, String fmt) throws InvalidObjectException {
        if (value != expect) {
            throw new InvalidObjectException(String.format("read %s error %d, expect %d",fmt, value, expect));
        }
    }
    protected static void verify(int value, int expect, String fmt) throws InvalidObjectException {
        if (value != expect) {
            throw new InvalidObjectException(String.format("read %s error %d, expect %d",fmt, value, expect));
        }
    }

    public void test(){
        mResult = new byte[30];
    }
    public void checkResult() throws InvalidObjectException {
    }

    public static int byteToInt(byte b) {
        return b&0xff;
    }
}
